package com.tous.tool.controller;

import com.tous.tool.service.VideoCompressionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;

/**
 * @author mengwei
 * @description StreamController
 * @createDate 2025/7/21 9:06
 */
@RestController
@RequestMapping("/api/stream/v1")
public class StreamController {


  private final Logger logger = LoggerFactory.getLogger(StreamController.class);

  @Autowired
  private VideoCompressionService compressionService;

  @GetMapping(value = "/emitter", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  public ResponseBodyEmitter streamLogs() {

    // 60秒超时
    ResponseBodyEmitter emitter = new ResponseBodyEmitter(60000L);
    // 启动异步线程处理日志生成
    Executors.newSingleThreadExecutor().execute(() -> {
      try {
        for (int i = 1; i <= 10; i++) {
          String logEntry = "[" + LocalDateTime.now() + "] 第" + i + "条日志\n";
          emitter.send(logEntry); // 发送日志条目
          Thread.sleep(1000); // 模拟日志生成延迟
        }
        emitter.complete(); // 日志发送完毕
      } catch (Exception e) {
        emitter.completeWithError(e); // 出现异常时终止
      }
    });
    // 设置超时回调
    emitter.onTimeout(() -> {
      logger.warn("日志流连接超时");
      emitter.completeWithError(new TimeoutException("连接超时"));
    });
    // 设置完成回调
    emitter.onCompletion(() -> logger.info("日志流连接已关闭"));
    return emitter;
  }


  private final String VIDEO_DIR = "videos";

  @GetMapping("/stream/{filename}")
  public ResponseEntity<StreamingResponseBody> streamVideo(
          @PathVariable String filename,
          @RequestParam(required = false, defaultValue = "original") String quality,
          @RequestHeader(value = "Range", required = false) String rangeHeader) throws IOException {

    Path originalPath = Paths.get(VIDEO_DIR, filename);
    File videoFile;

    switch (quality) {
      case "verylow":
        File veryLowFile = getCompressedVersion(filename, "verylow");
        if (!veryLowFile.exists()) {
          compressionService.compressVideo(
                  originalPath.toFile(),
                  veryLowFile,
                  426,  // 240p width
                  240,  // 240p height
                  300000 // 300kbps
          );
        }
        videoFile = veryLowFile;
        break;
      case "low":
        File lowFile = getCompressedVersion(filename, "low");
        if (!lowFile.exists()) {
          compressionService.compressVideo(
                  originalPath.toFile(),
                  lowFile,
                  640,  // 360p width
                  360,  // 360p height
                  500000 // 500kbps
          );
        }
        videoFile = lowFile;
        break;
      case "medium":
        File mediumFile = getCompressedVersion(filename, "medium");
        if (!mediumFile.exists()) {
          compressionService.compressVideo(
                  originalPath.toFile(),
                  mediumFile,
                  854,  // 480p width
                  480,  // 480p height
                  1000000 // 1Mbps
          );
        }
        videoFile = mediumFile;
        break;
      default:
        videoFile = originalPath.toFile();
    }

    // ...保持原有流处理逻辑
    if (!videoFile.exists()) {
      return ResponseEntity.notFound().build();
    }
    Resource videoResource = new UrlResource(videoFile.getAbsoluteFile().toURI());
    long fileSize = videoResource.contentLength();

    // 处理范围请求 (用于支持视频跳转)
    if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
      String[] ranges = rangeHeader.substring(6).split("-");
      long rangeStart = Long.parseLong(ranges[0]);
      long rangeEnd = ranges.length > 1 ? Long.parseLong(ranges[1]) : fileSize - 1;

      if (rangeEnd >= fileSize) {
        rangeEnd = fileSize - 1;
      }

      long contentLength = rangeEnd - rangeStart + 1;

      StreamingResponseBody responseBody = outputStream -> {
        try (InputStream inputStream = videoResource.getInputStream()) {
          inputStream.skip(rangeStart);
          byte[] buffer = new byte[1024 * 1024]; // 1MB buffer
          long bytesToRead = contentLength;

          while (bytesToRead > 0) {
            int bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, bytesToRead));
            if (bytesRead == -1) break;
            outputStream.write(buffer, 0, bytesRead);
            bytesToRead -= bytesRead;
          }
        }
      };

      return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
              .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
              .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength))
              .header(HttpHeaders.CONTENT_RANGE, "bytes " + rangeStart + "-" + rangeEnd + "/" + fileSize)
              .header(HttpHeaders.ACCEPT_RANGES, "bytes")
              .body(responseBody);
    } else {
      // 完整文件请求
      StreamingResponseBody responseBody = outputStream -> {
        try (InputStream inputStream = videoResource.getInputStream()) {
          byte[] buffer = new byte[1024 * 1024]; // 1MB buffer
          int bytesRead;
          while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
          }
        }
      };

      return ResponseEntity.ok()
              .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
              .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileSize))
              .header(HttpHeaders.ACCEPT_RANGES, "bytes")
              .body(responseBody);
    }
  }

  private File getCompressedVersion(String originalFilename, String quality) {
    String compressedDir = "compressed_videos/" + quality;
    new File(compressedDir).mkdirs();
    return new File(compressedDir, quality + "_" + originalFilename);
  }

}
